package ca.ubc.icapture.genapha.actions;

import ca.ubc.icapture.genapha.beans.AlleleCounts;
import ca.ubc.icapture.genapha.beans.AssociationResultBean;
import ca.ubc.icapture.genapha.beans.PopulationDiversityBean;
import ca.ubc.icapture.genapha.forms.SnpSummaryForm;
import icapture.beans.DB.EthnicityFrequency;
import icapture.beans.DB.SNPStatus;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.Action;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import icapture.SQLMgr;
import icapture.beans.DB.Cohort;
import icapture.beans.DB.SNP;
import icapture.beans.DB.Values;
import icapture.beans.KeggGeneBean;

import icapture.beans.KeggPathwayBean;
import icapture.beans.PageLink;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;

/**
 * Created by IntelliJ IDEA.
 * User: btripp
 * Date: Sep 13, 2006
 * Time: 9:39:08 AM
 * To change this template use File | Settings | File Templates.
 */
public class SnpSummaryAction extends Action
{

    @Override
    public ActionForward execute(ActionMapping mapping,
                                 ActionForm form,
                                 HttpServletRequest request,
                                 HttpServletResponse response)
    {

        ActionForward forward = new ActionForward();
        SnpSummaryForm snpSummaryForm = (SnpSummaryForm) form;

        SNP snp = null;
        try
        {
            snp = SQLMgr.getCachedSnp(snpSummaryForm.getRsNumber());
        }
        catch (Exception e)
        {
            e.printStackTrace();
            return mapping.findForward("home");
        }

        // General Information
        generalInfo(snp, snpSummaryForm);

        // Genotyping Status
        genoStatus(snp, snpSummaryForm);

        // Association Results
        assocResults(snp, snpSummaryForm);

        // Population Diversity
        popDiversity(snp, snpSummaryForm);

        // Build links
        links(snp, snpSummaryForm);

        forward = mapping.findForward("display");

        return forward;
    }

    private void generalInfo(SNP snp, SnpSummaryForm form)
    {
        form.setSnp(snp);
        form.setGeneSnpList(SQLMgr.getSNPs(snp.getGene()));

        // Gene Aliases
        ArrayList<String> aliases = SQLMgr.getGeneAlias(snp.getGene());
        Collections.sort(aliases);
        StringBuilder aliasBuilder = new StringBuilder();
        if (!aliases.isEmpty())
        {
            Iterator<String> aliasIter = aliases.iterator();
            String firstAlias = aliasIter.next();
            if (firstAlias.equalsIgnoreCase(snp.getGene().getName()))
            {
                if (aliasIter.hasNext())
                {
                    aliasBuilder.append(aliasIter.next());
                }
            }
            else
            {
                aliasBuilder.append(firstAlias);
            }
            while (aliasIter.hasNext())
            {
                String alias = aliasIter.next();
                if (!alias.equalsIgnoreCase(snp.getGene().getName()))
                {
                    aliasBuilder.append(", ").append(alias);
                }
            }
        }
        if (aliasBuilder.length() <= 0)
        {
            aliasBuilder.append("N/A");
        }
        form.setGeneAlias(aliasBuilder.toString());

        // SNP Aliases
        aliases = SQLMgr.getSNPAlias(snp);
        Collections.sort(aliases);
        aliasBuilder = new StringBuilder();
        if (!aliases.isEmpty())
        {
            Iterator<String> aliasIter = aliases.iterator();
            String firstAlias = aliasIter.next();
            if (firstAlias.equalsIgnoreCase(snp.getRsNumber()))
            {
                if (aliasIter.hasNext())
                {
                    aliasBuilder.append(aliasIter.next());
                }
            }
            else
            {
                aliasBuilder.append(firstAlias);
            }
            while (aliasIter.hasNext())
            {
                String alias = aliasIter.next();
                if (!alias.equalsIgnoreCase(snp.getRsNumber()))
                {
                    aliasBuilder.append(", ").append(alias);
                }
            }
        }
        if (aliasBuilder.length() <= 0)
        {
            aliasBuilder.append("N/A");
        }
        form.setSnpAlias(aliasBuilder.toString());

        form.setPrevAssociations(new Boolean(SQLMgr.isSnpInSet(snp, 0)));
    }

    private void genoStatus(SNP snp, SnpSummaryForm form)
    {
        ArrayList<SNPStatus> snpStatusList = new ArrayList<SNPStatus>();
        ArrayList<Cohort> cohortList = SQLMgr.getCohorts();
        for (Cohort cohort : cohortList)
        {
            SNPStatus snpStatus = SQLMgr.getSNPStatus(snp, cohort);
            snpStatusList.add(snpStatus);
        }
        form.setCohortList(cohortList);
        form.setSnpStatusList(snpStatusList);
    }

    private void assocResults(SNP snp, SnpSummaryForm form)
    {
        // Fill all AssociationResultBeans
        HashMap<String, AssociationResultBean> arbMap = new HashMap<String, AssociationResultBean>();
        ArrayList<Values> vals = SQLMgr.getValues(snp);
        for (Values val : vals)
        {
            String key = val.getCohort().getCohortID() + "-" + val.getPhenotype().getPhenotypeID();
            AssociationResultBean arb = arbMap.get(key);
            if (arb == null)
            {
                arb = new AssociationResultBean();
                arbMap.put(key, arb);
            }
            if (val.getExperiment().getExperimentID() == 0)
            {
                arb.setCombinedValues(val);
            }
            else if (val.getExperiment().getExperimentID() == 1)
            {
                arb.setCaucasianValues(val);
            }
            else if (val.getExperiment().getExperimentID() == 2)
            {
                arb.setNonCauacasianValues(val);
            }
        }
        // Build assocHelpList and pvalue map with the AssociationResultBeans built above
        HashMap<String, ArrayList<AssociationResultBean>> snpPValueMap = new HashMap<String, ArrayList<AssociationResultBean>>();
        for (AssociationResultBean arb : arbMap.values())
        {
            String key = arb.getPhenotype().getName();
            ArrayList<AssociationResultBean> valList = snpPValueMap.get(key);
            if (valList == null)
            {
                valList = new ArrayList<AssociationResultBean>();
                snpPValueMap.put(arb.getPhenotype().getName(), valList);
            }
            valList.add(arb);
        }
        // Sort AssociationResultBean by cohortid
        for (ArrayList<AssociationResultBean> list : snpPValueMap.values())
        {
            Collections.sort(list);
        }
        form.setSnpPValueMap(snpPValueMap);
    }

    private void popDiversity(SNP snp, SnpSummaryForm form)
    {
        ArrayList<PopulationDiversityBean> pdbList = new ArrayList<PopulationDiversityBean>();
        form.setPopulationDiversityList(pdbList);

        ArrayList<PopulationDiversityBean> caseControlPdbList = new ArrayList<PopulationDiversityBean>();
        form.setCaseControlDiversityList(caseControlPdbList);

        // Get ethnicity frequency data
        PopulationDiversityBean pdb = null;
        ArrayList<EthnicityFrequency> efList = SQLMgr.getEthnicityFrequency(snp);
        // There are multiple EthnicityFrequency per PopulationDiversityBean.
        // Therefore, maps are used to retrieve the corresponding PopulationDiversityBean.
        HashMap<String, PopulationDiversityBean> familyPDMap = new HashMap<String, PopulationDiversityBean>();
        HashMap<String, PopulationDiversityBean> caseControlPDMap = new HashMap<String, PopulationDiversityBean>();
        for (EthnicityFrequency ef : efList)
        {
            String key = ef.getCohort().getCohortID() + "-" + ef.getEthnicity().getEthnicityID();
            if (ef.getCode() == 1 || ef.getCode() == 3)
            {
                //family data
                pdb = familyPDMap.get(key);
                if (pdb == null)
                {
                    pdb = new PopulationDiversityBean();
                    pdb.setCohort(ef.getCohort());
                    pdb.setEthnicity(ef.getEthnicity());
                    familyPDMap.put(key, pdb);
                    pdbList.add(pdb);
                }
            }
            else
            {
                //case-control data
                pdb = caseControlPDMap.get(key);
                if (pdb == null)
                {
                    pdb = new PopulationDiversityBean();
                    pdb.setCohort(ef.getCohort());
                    pdb.setEthnicity(ef.getEthnicity());
                    caseControlPDMap.put(key, pdb);
                    caseControlPdbList.add(pdb);
                }
            }

            if (ef.getCode() == 1 || ef.getCode() == 4)
            {
                // Child's data
                AlleleCounts child = pdb.getChild();
                if (child == null)
                {
                    child = new AlleleCounts();
                    pdb.setChild(child);
                }
                if (ef.getAllele().equalsIgnoreCase(snp.getMajorAllele()))
                {
                    child.setAllele1Count(ef.getN());
                }
                else
                {
                    child.setAllele2Count(ef.getN());
                }
            }
            else if (ef.getCode() == 3 || ef.getCode() == 5)
            {
                // Parent's data
                AlleleCounts parent = pdb.getParent();
                if (parent == null)
                {
                    parent = new AlleleCounts();
                    pdb.setParent(parent);
                }
                if (ef.getAllele().equalsIgnoreCase(snp.getMajorAllele()))
                {
                    parent.setAllele1Count(ef.getN());
                }
                else
                {
                    parent.setAllele2Count(ef.getN());
                }
            }
        }

        // Iterates through two lists and calculates all allele counts
        for (PopulationDiversityBean pd : pdbList)
        {
            AlleleCounts child = pd.getChild();
            if (child != null)
            {
                child.calculate();
            }

            AlleleCounts parent = pd.getParent();
            if (parent != null)
            {
                parent.calculate();
            }
        }
        for (PopulationDiversityBean pd : caseControlPdbList)
        {
            AlleleCounts child = pd.getChild();
            if (child != null)
            {
                child.calculate();
            }

            AlleleCounts parent = pd.getParent();
            if (parent != null)
            {
                parent.calculate();
            }
        }
    }

    private void links(SNP snp, SnpSummaryForm form)
    {
        // Build SNP links
        PageLink snpLink = new PageLink();
        snpLink.setName("dbSNP");
        snpLink.setUrl("http://www.ncbi.nlm.nih.gov/SNP/snp_ref.cgi?rs=" + snp.getRsNumber());
        ArrayList<PageLink> snpLinks = new ArrayList<PageLink>();
        snpLinks.add(snpLink);
        form.setSnpLinks(snpLinks);

        // Build gene links
        ArrayList<PageLink> geneLinks = SQLMgr.getGeneLinks(snp.getGene());
        form.setGeneLinks(geneLinks);

        // Build pathway links
        ArrayList<PageLink> pathwayLinks = new ArrayList<PageLink>();
        for (String pathwayName : SQLMgr.getKeggPathways(snp.getGene()))
        {
            for (KeggPathwayBean kpb : SQLMgr.getKeggPathwayLike(pathwayName))
            {
                // Build KeggPathway page link
                PageLink page = new PageLink();
                page.setName(kpb.getName());

                StringBuilder url = new StringBuilder("http://www.genome.jp/dbget-bin/show_pathway?hsa");
                url.append(kpb.getId());
                for (KeggGeneBean kgb : kpb.getGeneList())
                {
                    url.append("+").append(kgb.getGeneId());
                }
                page.setUrl(url.toString());

                ArrayList<KeggGeneBean> kgbs = kpb.getGeneList();
                Collections.sort(kgbs);
                Iterator<KeggGeneBean> kgbIter = kgbs.iterator();
                StringBuilder title = new StringBuilder(kgbIter.next().getName());
                while (kgbIter.hasNext())
                {
                    title.append(", ").append(kgbIter.next().getName());
                }
                page.setTitle(title.toString());

                // Add the link to the list
                pathwayLinks.add(page);
            }
        }
        form.setPathwayLinks(pathwayLinks);
    }
}
